#pragma once

#include "GLShader.h"
#include "GLCamera.h"

#include <GLFW/glfw3.h>
#include <functional>
#include <vector>
#include <map>

#define USER_ARRAY_ID 1024
#define USER_TEXTURE_ID 1024
#define USER_PROGRAM_ID 1024

// 纹理类型
enum TEXTURE
{
	RED, GREEN, BLUE, YELLOW, WHITE, BLACK, CHESS
};

class GLScene;
class GLProgram
{
protected:
	GLProgram(int width, int height, const char* title, int& flag);
	~GLProgram();

	static GLProgram* s_program;

public:
	struct FrameID
	{
		unsigned int frameID;
		unsigned int textureID;
		unsigned int RBO;
	};

	static GLProgram* CreateProgram(int width, int height, const char* title, int& flag);
	static GLProgram* ShareProgram();
	static void DeleteProgram();

	GLScene* ShareScene();

	// uniform 变量操作
	void SetUniformInt(const char* var, int val);
	void SetUniformFloat(const char* var, float val);
	void SetUniformVec2(const char* var, const float* val);
	void SetUniformVec2(const char* var, float x, float y); 
	void SetUniformVec3(const char* var, const float* val);
	void SetUniformVec3(const char* var, float x, float y, float z);
	void SetUniformVec4(const char* var, const float* val);
	void SetUniformVec4(const char* var, float x, float y, float z, float w);
	void SetUniformMatrix4fv(const char* var, const float* val);
	void SetUniformBlock(const char* var, int i);

	// 光照操作
	void SetDirLight(glm::vec3 direction, glm::vec3 ambient, glm::vec3 diffuse, glm::vec3 specular);
	void SetPointLight(int i, glm::vec3 position, glm::vec3 ambient, glm::vec3 diffuse, glm::vec3 specular);
	void SetSpotLight(int i, glm::vec3 position, glm::vec3 direction, glm::vec3 ambient, glm::vec3 diffuse, glm::vec3 specular);

	// 着色器操作
	void GenerateProgram(int i, const char* vertexPath, const char* fragmentPath, const char* geometryPath = nullptr);
	void UseProgram(int i);
	void InitProgram();

	// 顶点数组操作
	void GenerateArray(int i);
	void BindArray(int i);
	void BindInsArray(int i);
	void UnbindArray();

	// uniform 缓冲操作
	void GenerateUBO(int i);
	void BindUBO(int i);
	void UnbindUBO();

	// 纹理操作
	void GenerateTexture(int i);
	void LoadTexture(const char* file);
	void LoadTexture(TEXTURE texture, float a = 1.0);
	void LoadTexture(std::vector<const char*> files);
	void ActiveTexture(int i);
	void BindTexture(int i);
	void BindCubeTexture(int i);
	void UnbindTexture();

	// 帧缓冲操作
	void GenerateFrame(int i);
	void BindFrame(int i);
	void UnbindFrame();

	// 用于生成屏幕顶点数组，绘制帧缓冲到屏幕上
	void GenerateScreenArray(int i);
	void DrawScreen(int array, int frame);

	// 用于生成天空盒顶点数组，绘制天空盒
	void GenerateSkyboxArray(int i);
	void DrawSkybox(int array, int texture);

	// 消息循环
	void MessageLoop(std::function<void(void)> loader,
		std::function<void(void)> painter);

protected:
	GLFWwindow* m_window;
	GLShader* m_shader;
	GLScene* m_scene;

	std::map<int, unsigned int> m_VAOs;			// 顶点数组对象 ID
	std::map<int, unsigned int> m_VBOs;			// 顶点缓冲对象 ID
	std::map<int, unsigned int> m_EBOs;			// 索引缓冲对象 ID
	std::map<int, unsigned int> m_Inss;			// 实例缓冲对象 ID
	std::map<int, unsigned int> m_UBOs;			// uniform 缓冲对象 ID
	std::map<int, unsigned int> m_textures;		// 2D 纹理 ID
	std::map<int, FrameID> m_frames;			// 帧缓冲对象 ID
	std::map<int, GLShader*> m_shaders;			// 保存着色器

public:
	static GLCamera s_camera;
	static bool s_moving;
};

void GLFWWindowResize(GLFWwindow* window, int width, int height);
void GLFWMouseButtonCallback(GLFWwindow* window, int button, int action, int mode);
void GLFWCursorPosCallback(GLFWwindow* window, double xpos, double ypos);
void GLFWScrollCallback(GLFWwindow* window, double xoffset, double yoffset);